#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include "l0001-0/l0001-0.h"
#include "l0002-0/l0002-0.h"
#include "cJSON.h"
#include "parser.h"

#define MODNAME "[PSR]"

struct l0032_iniconf_parser iniconf_parser = {
	.context = NULL,
	.ncontext = 0,
};

void l0032_reinit_iniconf_parser(struct l0032_iniconf_parser *parser, int maxdepth)
{
	free(parser->context);
	parser->ncontext = 0;
	parser->top = -1;
	parser->context = zmalloc(sizeof(struct l0032_parser_context) * maxdepth);
	if (parser->context) {
		parser->ncontext = maxdepth;
	}
}

static void l0032_parser_expand(struct l0032_iniconf_parser *parser)
{
    struct l0032_parser_context *context = zmalloc(sizeof(struct l0032_parser_context) * parser->ncontext * 2);
    int i;
    if (context) {
        for (i = 0;i < parser->ncontext;i ++) {
            memcpy(&context[i], &parser->context[i], sizeof(struct l0032_parser_context));
        }
        parser->ncontext *= 2;
        parser->context = context;
    }
    
}

void l0032_iniconf_set_expect(struct l0032_iniconf_parser *parser, const char* stream, ...)
{
    if (parser->top >= 0) {
        va_list arg_ptr;
        va_start(arg_ptr, stream);
        vsnprintf(parser->context[parser->top].expect, L0032_PARSER_CONTEXT_BUFLEN, stream, arg_ptr);
        va_end(arg_ptr);
    }
}

void l0032_iniconf_clear_expect(struct l0032_iniconf_parser *parser, const char* expect)
{
    if (parser->top >= 0) {
        memset(parser->context[parser->top].expect, 0, L0032_PARSER_CONTEXT_BUFLEN);
    }
}

void l0032_iniconf_set_errmessage(struct l0032_iniconf_parser *parser, const char* stream, ...)
{
    va_list arg_ptr;
    va_start(arg_ptr, stream);
    if (parser->top >= 0) {
        // printf("parser %p\n", parser);
        // printf("stream %s\n", stream);
        // printf("message %s\n", parser->context[parser->top].errmessage);
        // printf("%p\n", arg_ptr);
        vsnprintf(parser->context[parser->top].errmessage, L0032_PARSER_CONTEXT_BUFLEN, stream, arg_ptr);
    }
    va_end(arg_ptr);
}

void l0032_iniconf_clear_errmessage(struct l0032_iniconf_parser *parser)
{
    if (parser->top >= 0) {
        memset(parser->context[parser->top].errmessage, 0, L0032_PARSER_CONTEXT_BUFLEN);
    }
}

void l0032_iniconf_context_push(struct l0032_iniconf_parser *parser, const char* stream, ...)
{
    // ERRSYS_FATALPRINT("push context %s\n", stream);
    if (parser->top + 1 == parser->ncontext) {
        l0032_parser_expand(parser);
    }
    if (parser->top + 1 < parser->ncontext) {
        struct l0032_parser_context *context;
        va_list arg_ptr;
        va_start(arg_ptr, stream);

        parser->top ++;
        context = &parser->context[parser->top];
        vsnprintf(context->nodename, L0032_PARSER_CONTEXT_BUFLEN, stream, arg_ptr);
        // ERRSYS_FATALPRINT("nodename %s\n", context->nodename);
        va_end(arg_ptr);
    }
}

void l0032_iniconf_context_pop(struct l0032_iniconf_parser *parser)
{
    parser->top --;
    if (parser->top < -1) {
        parser->top = -1;
    }
}

void l0032_parser_dump(struct l0032_iniconf_parser *parser)
{
    int i;
    ERRSYS_FATALPRINT("###### INICONF PARSER DUMP BEGIN ######\n");
    ERRSYS_FATALPRINT("parser top %d\n", parser->top);
    for (i = 0;i <= parser->top;i ++) {
        ERRSYS_FATALPRINT("%*s%s\n", i, "", parser->context[i].nodename);
    }
    if (parser->top >= 0) {
        if (strlen(parser->context[parser->top].errmessage) != 0 && strlen(parser->context[parser->top].expect) != 0) {
            ERRSYS_FATALPRINT("*** error in parsing \"%s\", %s\n", parser->context[parser->top].expect, parser->context[parser->top].errmessage);
        }
        else if (strlen(parser->context[parser->top].expect) != 0) {
            ERRSYS_FATALPRINT("*** error in parsing \"%s\"\n", parser->context[parser->top].expect);
        }
        else if (strlen(parser->context[parser->top].errmessage) != 0) {
            ERRSYS_FATALPRINT("*** error:%s\n", parser->context[parser->top].errmessage);
        }
    }

    if (parser->top < 0) {
        ERRSYS_FATALPRINT("context is empty.\n");
    }
    ERRSYS_FATALPRINT("###### INICONF PARSER DUMP END  ######\n");
}